package io.jee.medusa.alibaba.aliyun;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.cdn.model.v20141111.SetCcConfigRequest;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.HttpResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;

import io.jee.medusa.util.PropertiesUtils;

public class CCFirewallHelper {
	
	protected final Log logger = LogFactory.getLog(getClass());
	
	private PropertiesUtils propertiesUtils = PropertiesUtils.loadProperties("ccfirewall.properties");

	private Map<String, CCFirewallModel> data = new HashMap<>();
	private Map<String, Integer> submitData = new HashMap<>();
	private IAcsClient client = null;
	
	private int minute = 1000*60;
	
	private Set<String> preSubmitData = new HashSet<>();
	
	private Set<String> whiteIps = new HashSet<>();
	
	String accessKeyId, secret, domainName;
	
	private static CCFirewallHelper ccFirewallHelper;
	
	private static int count = 0;
	
	public static synchronized CCFirewallHelper getInstance(){
		if(null == ccFirewallHelper){
			ccFirewallHelper = new CCFirewallHelper();
		}
		return ccFirewallHelper;
	}
	
	public CCFirewallHelper() {
		accessKeyId = propertiesUtils.getRequiredValue("accessKeyId");
		secret = propertiesUtils.getRequiredValue("secret");
		domainName = propertiesUtils.getRequiredValue("domainName");
		
		String proWhiteIps = propertiesUtils.getRequiredValue("whiteIps");
		if(StringUtils.isNotBlank(proWhiteIps)){
			try {
				for (String whiteIp : proWhiteIps.split(",")) {
					whiteIp = InetAddress.getByName(whiteIp.trim()).getHostAddress();
					whiteIps.add(whiteIp);
				}
			} catch (UnknownHostException e) {
				logger.error(e.getMessage());
			}
		}
		if(count++>0){
			throw new RuntimeException("CC防火墙不是这么用的，需要调用getInstance()");
		}
		if (null == client) {
            try {
                init();
            } catch (ClientException e) {
                e.printStackTrace();
            }
        }
		Timer timer = new Timer();
		timer.schedule(new Task(), 1000, 10*60*1000);
	}
	
    @SuppressWarnings("unchecked")
	public void init() throws ClientException {
//      初始化IAcsClient
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, secret);
        //DefaultProfile.addEndpoint("cn-hangzhou-2", "cn-hangzhou-2", "Cdn", "cdn.aliyuncs.com"); //添加自定义endpoint。
        client = new DefaultAcsClient(profile);
        //System.setProperty("http.proxyHost", "127.0.0.1"); //此设置用于设置代理，可用fiddler拦截查看http请求，便于调试。
        //System.setProperty("http.proxyPort", "8888");
        File file=new File(System.getProperty("java.io.tmpdir"),"blockIps.data");
        if(file.exists()){
        	try {
    			ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
    			submitData = (Map<String, Integer>) ois.readObject();
    			preSubmitData.addAll(submitData.keySet());
    			if(ois!=null){
    				ois.close();
    			}
    		} catch (IOException | ClassNotFoundException e) {
    			logger.error(e.getMessage());
    		}
        }
    }
	
	public void put(String ip){
		if(!whiteIps.contains(ip)){
			CCFirewallModel firewallModel = data.get(ip);
			if(firewallModel==null){
				data.put(ip, new CCFirewallModel(1, (int) (System.currentTimeMillis()/minute), (int) (System.currentTimeMillis()/minute/60)));
			}else{
				firewallModel.setCount(firewallModel.getCount()+1);
				firewallModel.setLastminute((int) (System.currentTimeMillis()/minute));
			}
		}
	}
	
	public void submit(){
		String proWhiteIps = propertiesUtils.getRequiredValue("whiteIps");
		whiteIps.clear();
		if(StringUtils.isNotBlank(proWhiteIps)){
			try {
				for (String whiteIp : proWhiteIps.split(",")) {
					whiteIp = InetAddress.getByName(whiteIp.trim()).getHostAddress();
					whiteIps.add(whiteIp);
				}
			} catch (UnknownHostException e) {
				logger.error(e.getMessage());
			}
		}
		
		Iterator<Entry<String, Integer>> iteratorSubmit = submitData.entrySet().iterator();
		while (iteratorSubmit.hasNext()) {
			Entry<String, Integer> entry = iteratorSubmit.next();
			int hour = entry.getValue();
			if(((System.currentTimeMillis()/minute/60)-hour)>=24){
				iteratorSubmit.remove();
			}
		}
		Iterator<Entry<String, CCFirewallModel>> iterator = data.entrySet().iterator();
		while (iterator.hasNext()) {
			Entry<String, CCFirewallModel> entry = iterator.next();
			CCFirewallModel firewallModel = entry.getValue();
			if(((System.currentTimeMillis()/minute) - firewallModel.getLastminute())>60){
				iterator.remove();
			}else if(((System.currentTimeMillis()/minute/60) - firewallModel.getStarthour())>=24){
				iterator.remove();
			}else if(firewallModel.getCount()>1000&&submitData.size()<100){
				submitData.put(entry.getKey(), (int) (System.currentTimeMillis()/minute/60));
				iterator.remove();
			}
		}
		
		if(!submitData.keySet().equals(preSubmitData)){
			SetCcConfigRequest setCcConfigRequest = new SetCcConfigRequest();
	        setCcConfigRequest.setDomainName(domainName);
	        setCcConfigRequest.setEnable("on");
	        setCcConfigRequest.setBlockIps(StringUtils.join(submitData.keySet(), ","));
	        
	        try {
				HttpResponse httpResponse = client.doAction(setCcConfigRequest);
				if(httpResponse.isSuccess()){
					logger.warn("阿里云防火墙提交:"+submitData);
					preSubmitData.clear();
					preSubmitData.addAll(submitData.keySet());
					try{
						ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(System.getProperty("java.io.tmpdir"),"blockIps.data")));
						oos.writeObject(submitData);
						oos.flush();
						oos.close();
					}catch(IOException e){
						System.err.println(e.getMessage());
					}
				}else{
					logger.error("阿里云防火墙提交失败:"+new String(httpResponse.getContent()));
				}
			} catch (ClientException e) {
				logger.error(e.getMessage());
			}
		}
	}
	
	class Task extends TimerTask {

		@Override
		public void run() {
			submit();
		}

	}
	
	class CCFirewallModel {
		
		private int count;
		private int lastminute;
		private int starthour;
		
		public CCFirewallModel(int count, int lastminute, int starthour) {
			this.count = count;
			this.lastminute = lastminute;
			this.starthour = starthour;
		}

		public int getCount() {
			return count;
		}

		public void setCount(int count) {
			this.count = count;
		}

		public int getLastminute() {
			return lastminute;
		}

		public void setLastminute(int lastminute) {
			this.lastminute = lastminute;
		}

		public int getStarthour() {
			return starthour;
		}

		public void setStarthour(int starthour) {
			this.starthour = starthour;
		}
		
	}

}
